﻿using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OutputCaching;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.BlobStoring;

namespace Jy.Abp.BlobStoring;

[ApiController]
public abstract class BlobControllerBase : AbpController
{
    public const string DefaultContainerName = DefaultContainer.Name;

    protected string CreatePermissionName;
    protected string GetPermissionName;
    protected string DeletePermissionName;

    protected readonly IBlobContainerFactory BlobContainerFactory;

    public BlobControllerBase(IBlobContainerFactory blobContainerFactory)
    {
        BlobContainerFactory = blobContainerFactory;
    }
    protected virtual string GetAutoDirName(BlobAutoDirType? type)
    {
        switch (type)
        {
            case BlobAutoDirType.Year:
                return DateTime.Now.ToString("yyyy");
            case BlobAutoDirType.Month:
                return DateTime.Now.ToString("yyyyMM");
            case BlobAutoDirType.Day:
                return DateTime.Now.ToString("yyyyMMdd");
            default:
                return null;
        }
    }

    protected virtual async Task CheckPolicyAsync(string policyName)
    {
        if (!string.IsNullOrEmpty(policyName))
        {
            await AuthorizationService.CheckAsync(policyName).ConfigureAwait(continueOnCapturedContext: false);
        }
    }

    protected virtual string GetFileName(BlobUploadInput input)
    {
        var fileExt = Path.GetExtension(input.File.FileName).ToLower();
        if (!MimeTypeNames.Maps.ContainsKey(fileExt))
            throw new UserFriendlyException(L["File type not supported"]);
        var fileName = input.Name;
        if (fileName.IsNullOrEmpty())
            fileName = $"{DateTime.Now.ToString("yyyyMMddHHmmss")}{new Random(Guid.NewGuid().GetHashCode()).Next(1000, 9999)}{fileExt}";
        var autoDir = GetAutoDirName(input.AutoDirType);
        if (autoDir.HasValue())
            return $"{autoDir}/{fileName}";
        return fileName;
    }

    protected virtual string GetUrl(string containerName, string blobName)
    {
        return $"{HttpContext.Request.Path}/{containerName}/{blobName}";
    }

    /// <summary>
    /// 上传文件
    /// </summary>
    [HttpPost]
    public virtual async Task<BlobSaveResult> CreateAsync([FromForm] BlobUploadInput input)
    {
        await this.CheckPolicyAsync(this.CreatePermissionName);

        var containerName = input.ContainerName ?? DefaultContainerName;
        var blobName = GetFileName(input);

        if (!Path.HasExtension(blobName))
        {
            var fileExt = Path.GetExtension(input.File.FileName).ToLower();
            blobName = $"{blobName}{fileExt}";
        }
        using (var stream = input.File.OpenReadStream())
        {
            await BlobContainerFactory
                .Create(containerName)
                .SaveAsync(blobName, stream, true);
        }
        return new BlobSaveResult()
        {
            ContainerName = containerName,
            Name = blobName,
            Url = GetUrl(containerName, blobName),
        };
    }
    /// <summary>
    /// 获取文件，会自动根据文件名称后缀名来设置返回的ContentType
    /// </summary>
    [OutputCache]
    [HttpGet("{containerName}/{**name}")]
    public virtual async Task<ActionResult> GetAsync(string containerName, string name)
    {
        await this.CheckPolicyAsync(this.GetPermissionName);

        var content = await BlobContainerFactory
                .Create(containerName)
                .GetOrNullAsync(name);
        if (content == null)
            return new NotFoundResult();
        var fileExt = Path.GetExtension(name)?.ToLower();
        if (fileExt.HasValue() && MimeTypeNames.Maps.TryGetValue(fileExt, out var mimeType))
            return new FileStreamResult(content, mimeType);
        return new FileStreamResult(content, MimeTypeNames.ApplicationOctetStream);
    }
    /// <summary>
    /// 删除文件
    /// </summary>
    [HttpDelete("{containerName}/{**name}")]
    public virtual async Task<bool> DeleteAsync(string containerName, string name)
    {
        await this.CheckPolicyAsync(this.DeletePermissionName);

        return await BlobContainerFactory
            .Create(containerName)
            .DeleteAsync(name);
    }
}
